/**
 * 西门子PLC适配器
 * 适用于西门子S7-1200和S7-1500系列PLC
 */
const ModbusTCPClient = require('../core/modbus-tcp-client');
const PLCAdapter = require('./plc-adapter');
const logger = require('../utils/logger');

class SiemensPLCAdapter extends PLCAdapter {
  constructor(device) {
    super(device);
    this.tagMap = new Map();
    
    // 初始化标签映射
    if (device.tags && Array.isArray(device.tags)) {
      device.tags.forEach(tag => {
        this.tagMap.set(tag.name, tag);
      });
    }
  }

  /**
   * 初始化PLC连接
   */
  async initialize() {
    try {
      logger.info(`[${this.device.id}] 初始化西门子PLC连接: ${this.device.name}`);
      
      if (this.device.protocol === 'ModbusTCP') {
        this.client = new ModbusTCPClient({
          id: this.device.id,
          ip: this.device.ip,
          port: this.device.port,
          unitId: this.device.unitId,
          autoReconnect: true,
          reconnectInterval: 5000,
          maxReconnectAttempts: 10
        });
        
        // 注册事件处理
        this.client.on('connected', () => {
          this.connected = true;
          this.emit('connected');
        });
        
        this.client.on('disconnected', () => {
          this.connected = false;
          this.emit('disconnected');
        });
        
        this.client.on('error', (error) => {
          this.emit('error', error);
        });
        
        this.client.on('reconnectFailed', () => {
          this.emit('reconnectFailed');
        });
        
        // 连接到PLC
        await this.client.connect();
        
        // 启动心跳检测
        this.startHeartbeat(30000);
        
        return this.connected;
      } else {
        throw new Error(`不支持的协议: ${this.device.protocol}`);
      }
    } catch (error) {
      logger.error(`[${this.device.id}] 初始化西门子PLC连接失败: ${error.message}`);
      throw error;
    }
  }

  /**
   * 断开PLC连接
   */
  async disconnect() {
    try {
      logger.info(`[${this.device.id}] 断开西门子PLC连接: ${this.device.name}`);
      
      // 停止所有轮询
      this.stopAllPolling();
      
      // 停止心跳检测
      this.stopHeartbeat();
      
      if (this.client) {
        await this.client.disconnect();
        this.connected = false;
      }
      
      return true;
    } catch (error) {
      logger.error(`[${this.device.id}] 断开西门子PLC连接失败: ${error.message}`);
      throw error;
    }
  }

  /**
   * 读取标签值
   * @param {string} tagName - 标签名称
   */
  async readTag(tagName) {
    try {
      if (!this.connected) {
        throw new Error('PLC未连接');
      }
      
      const tag = this.tagMap.get(tagName);
      if (!tag) {
        throw new Error(`标签不存在: ${tagName}`);
      }
      
      const { type, address } = this.parseAddress(tag.address);
      let data;
      
      switch (type) {
        case 'coil':
          data = await this.client.readCoils(address, 1);
          return this.convertDataType(data, tag.dataType, tag.scaleFactor);
        
        case 'discreteInput':
          data = await this.client.readDiscreteInputs(address, 1);
          return this.convertDataType(data, tag.dataType, tag.scaleFactor);
        
        case 'inputRegister':
          // 根据数据类型确定读取的寄存器数量
          const irCount = tag.dataType === 'float' || tag.dataType === 'int32' || tag.dataType === 'uint32' ? 2 : 1;
          data = await this.client.readInputRegisters(address, irCount);
          return this.convertDataType(data, tag.dataType, tag.scaleFactor);
        
        case 'holdingRegister':
          // 根据数据类型确定读取的寄存器数量
          const hrCount = tag.dataType === 'float' || tag.dataType === 'int32' || tag.dataType === 'uint32' ? 2 : 1;
          data = await this.client.readHoldingRegisters(address, hrCount);
          return this.convertDataType(data, tag.dataType, tag.scaleFactor);
        
        default:
          throw new Error(`不支持的地址类型: ${type}`);
      }
    } catch (error) {
      logger.error(`[${this.device.id}] 读取标签失败: ${tagName}, 错误: ${error.message}`);
      throw error;
    }
  }

  /**
   * 写入标签值
   * @param {string} tagName - 标签名称
   * @param {any} value - 写入值
   */
  async writeTag(tagName, value) {
    try {
      if (!this.connected) {
        throw new Error('PLC未连接');
      }
      
      const tag = this.tagMap.get(tagName);
      if (!tag) {
        throw new Error(`标签不存在: ${tagName}`);
      }
      
      const { type, address } = this.parseAddress(tag.address);
      const registers = this.convertToRegisters(value, tag.dataType, tag.scaleFactor);
      
      switch (type) {
        case 'coil':
          await this.client.writeSingleCoil(address, !!value);
          break;
        
        case 'holdingRegister':
          if (registers.length === 1) {
            await this.client.writeSingleRegister(address, registers[0]);
          } else {
            await this.client.writeMultipleRegisters(address, registers);
          }
          break;
        
        case 'discreteInput':
        case 'inputRegister':
          throw new Error(`无法写入只读地址类型: ${type}`);
        
        default:
          throw new Error(`不支持的地址类型: ${type}`);
      }
      
      logger.info(`[${this.device.id}] 成功写入标签: ${tagName}, 值: ${value}`);
      return true;
    } catch (error) {
      logger.error(`[${this.device.id}] 写入标签失败: ${tagName}, 值: ${value}, 错误: ${error.message}`);
      throw error;
    }
  }

  /**
   * 读取所有标签值
   */
  async readAllTags() {
    try {
      if (!this.connected) {
        throw new Error('PLC未连接');
      }
      
      const result = {};
      const tagNames = Array.from(this.tagMap.keys());
      
      for (const tagName of tagNames) {
        try {
          result[tagName] = await this.readTag(tagName);
        } catch (error) {
          logger.error(`[${this.device.id}] 读取标签失败: ${tagName}, 错误: ${error.message}`);
          result[tagName] = null;
        }
      }
      
      return result;
    } catch (error) {
      logger.error(`[${this.device.id}] 读取所有标签失败: ${error.message}`);
      throw error;
    }
  }

  /**
   * 发送心跳检测
   */
  async sendHeartbeat() {
    if (this.client && this.connected) {
      return await this.client.sendHeartbeat();
    }
    return false;
  }
}

module.exports = SiemensPLCAdapter;
